package cn.edward.camp.core;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.time.Duration;

public class RpcStub implements InvocationHandler {

    private static final OkHttpClient HTTP_CLIENT;

    static {
        HTTP_CLIENT = new OkHttpClient.Builder()
                .readTimeout(Duration.ofSeconds(16))
                .connectTimeout(Duration.ofSeconds(8))
                .build();
    }

    @SuppressWarnings("unchecked")
    public static <T> T create(Class<T> clazz) {
        return (T) Proxy.newProxyInstance(RpcStub.class.getClassLoader(), new Class[]{clazz}, new RpcStub());
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        RpcRequest rpcRequest = new RpcRequest();
        rpcRequest.setService(method.getDeclaringClass().getName());
        rpcRequest.setMethod(method.getName());
        rpcRequest.setParams(args);

        String json = JSON.toJSONString(rpcRequest, SerializerFeature.WriteClassName);
        MediaType contentType = MediaType.parse("application/json; charset=UTF-8");
        RequestBody requestBody = RequestBody.create(contentType, json);
        Request request = new Request.Builder().url("http://127.0.0.1:8088/rpc").post(requestBody).build();
        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            if (response.body() != null) {
                RpcResponse rpcResponse = JSON.parseObject(response.body().string(), RpcResponse.class);
                ParserConfig parserConfig = new ParserConfig();
                parserConfig.setAutoTypeSupport(true);
                return JSON.parse(String.valueOf(rpcResponse.getResult()), parserConfig);
            }
        }
        return RpcResponse.errorResponse().getResult();
    }
}
